home *** CD-ROM | disk | FTP | other *** search
- /* fbbfwd.c */
- /* Copyright P. Hardie VE5VA 1993 */
- #include "mb.h"
-
- /* Once the compression code is done, the program will have to force
- transparent mode on. The option letter C allows or disallows FBB
- compression (and therefore prevents use of transparent mode if, for
- some reason, it doesn't work.
- */
-
- char fbb_direction; /* Tells us whether we called or were called. */
- extern char optflags[];
- /* From mbfwd */
- #define fw_tiout 0x0010 /* Forward timeout flag */
- extern word fopts; /* Options, see defines above. */
- extern char path[80]; /* "G" item saved here, for logging */
- extern char fcall[10]; /* Call of the MailBox to forward to */
- /* From mbmail */
- #define ln_hier 64
- extern int hasbid, needbid, holdit;
- extern char fbb_flag;
-
- char *proposal = 0;
- short lastmsg,fbb_empty = 0;
- short msg_nr[10][2];
- extern char tmpstr[];
-
- fbbfwd(recno)
- int recno;
- {
- lastmsg = recno;
- fbb_empty = 0;
- if((proposal = malloc(80*20L)) == 0) {
- ttputs("Can't get memory for FBB forwarding\n");
- return;
- }
- #ifdef MCH_ZOO
- if(s_mart & zoook) {
- if(zoo_alloc()) {
- ttputs("Can't malloc enough space for ZOO transfer\n");
- return;
- }
- }
- else
- #endif
- if(s_mart & cmpok) {
- if(fbb_alloc()) {
- ttputs("Can't malloc enough space for FBB transfer\n");
- return;
- }
- }
- log ('M', 'F', 'S', "");
- if(fbb_direction)goto rcv;
-
- /* If compression is on and allowed and we're not already transparent,
- then force transparent mode.
- This is deliberately placed here and in rcv_fbb because forcing into
- command mode while the other end is sending the proposal immediately
- after its SID (because it connected to me) can cause loss of characters.
- The real problem is that you can miss the proposal altogether (if it was
- just FF) and then hang there waiting for a reply which won't come.
- */
- if((s_mart & (cmpok | zoook)) && !(port->flags&p_trans)) {
- cmdtnc();
- trantnc();
- }
- while(1) {
- /* Sends a proposal, gets reply, and sends messages if any */
- if(sndfbb())break;
- rcv:
- /* Receives a proposal, sends reply, and receives messages if any */
- if(rcvfbb())break;
- }
- free(proposal);
- #ifdef MCH_ZOO
- zoo_free();
- #endif
- fbb_free();
- log ('M', 'F', 'E', "");
- return;
- }
-
- /* rcv the fbb proposal and act on it */
- rcvfbb()
- {
- register int i,j;
- register char *p,*q;
- char c;
- char *prop[20];
- char fbbreply[15];
- int propsum;
-
- propsum = 0;
- i = 0;
- p = proposal;
- while(1) {
- port->line[0]=0;
- getdat();
- if((port->mode & gone) || (port->line[0] != 'F')) {
- fbb_release(0);
- return(1);
- }
- /* Release any previously sent messages.
- Unfortunately this can clobber port->line so it has to be
- temporarily saved from harm.
- */
- strcpy(tmpstr,port->line);
- fbb_release(1);
- strcpy(port->line,tmpstr);
- c = port->line[1];
- if(c == 'F') {
- fbb_empty = 1;
- return(0);
- }
- if(c == '>')break;
- if(c == 'Q') {
- return(1);
- }
- if((!(s_mart&(cmpok|zoook)) && (c == 'B')) ||
- ((s_mart&(cmpok|zoook)) && (c == 'A'))) {
- prop[i] = p;
- strcpy(p,port->line);
- while(*p && (*p != '\n')) {
- propsum += *p;
- p++;
- }
- /* Add a CR to checksum instead of LF
- */
- propsum += '\r';
- if(*p) *p++ = 0;
- else p++;
- i++;
- continue;
- }
-
- sprintf(tmpstr,"Unknown FBB command %02x '%s'\n",*port->line,port->line);
- ttputs(tmpstr);
- return(2);
- }
- /*
- This correctly computes the checksum which is sent after a proposal in
- compressed mode.
- printf("propsum = %02x -> %02x\n",propsum&0xff,(-propsum)&0xff);
- */
- /* We get here only if a F> has been received. So 'i' better not be zero */
- if(i == 0) {
- ttputs("FBB error: F> was not preceded by proposals\n");
- return(3);
- }
- /*
- If compression is on then check the checksum if it is there.
- If we're not already transparent, then force transparent mode.
- */
- if(s_mart & (cmpok|zoook)) {
- if((j = fromhex(&port->line[2])) >= 0) {
- propsum += j;
- if(propsum & 0xff) {
- outstr("*** Protocol error - F> Checksum\n");
- return(1);
- }
- }
- if(!port->flags&p_trans) {
- cmdtnc();
- trantnc();
- }
- }
- /* Now go through the proposal list and make up an FS reply */
- strcpy(fbbreply,"FS ");
- q = &fbbreply[3];
- for(j=0;j<i;j++) {
- fbb_parse(prop[j]);
-
- if(fbb_test()) {
- *q++ = '-';
- prop[j] = 0;
- }
- else {
- *q++ = '+';
- }
- }
- *q++ = '\n';
- *q = 0;
- ttputs("*");
- outstr(fbbreply);
- /*
- Now read the message(s).
- */
- for(j=0;j<i;j++) {
- if(prop[j] == 0)continue;
- /* Receive this message */
- initmsg(true);
- /* Parse the field again, but this time for real */
- fbb_parse(prop[j]);
- replace_bbs();
- if(port->mmhs->ext != 2)port->mmhs->ext = 0;
- dodis();
- if(port->mmhs->type == 'B')port->mmhs->lifetime = tstaleb;
- else port->mmhs->lifetime = 0;
- if(!(s_mart & (cmpok|zoook)))get_title();
- msgfile(port->cmd,mfhs->next_msg);
- if(s_mart & (cmpok|zoook)) {
- if(rcv_yapp(port->cmd))return(1);
- }
- else {
- if(!uloadm(port->cmd))return(1);
- }
- cremsg(); /* This writes the log record */
- }
- return(0);
- }
- sndfbb()
- {
- register int i,j;
- int extnr;
- register PORTS *p;
- register char *q;
- short msgnr;
- char fbbreply[15];
- unsigned int fbb_size;
-
- /* Clear the msg proposal area */
- for(i=0;i<5;i++)msg_nr[i][0] = 0;
- fbb_size;
- p = port;
- if(lastmsg == 0) {
- ttputs("*");
- if(fbb_empty) {
- outstr("FQ\n");
- return(1);
- }
- outstr("FF\n");
- return(0);
- }
- i = 0;
- j = 0;
- for(;lastmsg > 0;lastmsg--) {
- read_rec(mfl, lastmsg, (char *)p->mmhs);
- if((extnr = check_ok()) == 0)continue;
- p->mmhs->stat setbit m_busy;
- wt_mmhs();
- /* Store info about current message and send proposal */
- if(extnr > 0)extnr -= 1;
- msg_nr[i][0] = lastmsg;
- msg_nr[i][1] = extnr;
- fbb_flag = 1;
- if(s_mart & (cmpok|zoook)) {
- if((s_mart&hidok)and(p->mmhs->ext is 2))
- prtx("FA $B $P $h $G $b $s");
- else
- prtx("FA $B $P $A $G $b $s");
- }
- else {
- if((s_mart&hidok)and(p->mmhs->ext is 2))
- prtx("FB $B $P $h $G $b $s");
- else
- prtx("FB $B $P $A $G $b $s");
- }
- fbb_size += p->mmhs->size;
- fbb_flag = 0;
- /* Compute the checksum.
- It's best not to put the \n in the prtx string because, with
- fbb_flag on, prtx maps \n into \r\n
- */
- for(q=tmpstr;*q;q++) {
- j += *q;
- }
- j += '\r';
- ttputs("*");
- outstr(tmpstr);
- outchar('\n');
- i++;
- if((i == 5) || (fbb_size > 10000)) {
- /* Count this last message because breaking from the loop would
- avoid it
- */
- lastmsg--;
- break;
- }
- }
- if(i == 0) {
- ttputs("*");
- outstr("FF\n");
- return(0);
- }
- ttputs("*");
- if(s_mart & (cmpok|zoook)) {
- sprintf(tmpstr,"F> %02x\n",(-j)&0xff);
- tmpstr[3] = toupper(tmpstr[3]);
- tmpstr[4] = toupper(tmpstr[4]);
- outstr(tmpstr);
- }
- else {
- outstr("F>\n");
- }
- /* Now get their answer and see if they want any of them */
- getdat();
- if(p->mode & gone) {
- release:
- fbb_release(0);
- return(1);
- }
- if((port->line[1] != 'S') || (port->line[2] != ' ')) {
- if(port->line[0] == '*') {
- ttputs("FBB error from remote end or disconnect\n");
- }
- else {
- ttputs("Invalid FS reply!\n");
- }
- goto release;
- }
- strncpy(fbbreply,port->line,14);
- /*
- The FBB forwarding is now done in three stages.
- 1. Make sure that the number of replies on the FS line is exactly
- the same as the number of proposals that we sent. If they are
- not we can't be sure which message any of them refers to.
- 2. Go through the replies and release messages which are deferred
- (=), and mark as forwarded then release those which are rejected
- (-).
- 3. Go through the replies again and this time send those messages
- which were accepted (+).
- The reason for this process is that first of all we can't proceed
- unless the FS reply appears to be valid. Secondly, if the link drops
- during transfer of messages it doesn't change the fact that messages
- which were rejected should be marked as such and the deferred ones
- don't matter anyway. But if the link drops, all messages which
- were accepted should NOT be marked as forwarded.
- Note that when this routine finishes sending the requested messages,
- it doesn't mark them. That is done at the beginning of the rcvfbb
- routine after it has received a valid prompt of some sort from the
- other end. Otherwise it doesn't mark the messages and it aborts the
- connection.
- So, here we go.
- */
-
- /* 1.
- Make sure the number of replies in the FS line equals the number
- of proposals that we sent
- */
- q = &fbbreply[3];
- for(j=0;j<5;j++,q++) {
- if(*q == '-')continue;
- if(*q == '=')continue;
- if(*q == '+')continue;
- break;
- }
- if(j != i) {
- outstr("*** Protocol error in FS\n");
- goto release;
- }
-
- /* 2.
- Before doing the forwarding, remove those that are refused or deferred
- There's no point waiting until the prompt after I've sent the files
- that need to be sent because if the link dies, it doesn't change the
- fact that they don't want these messages.
- */
- q = &fbbreply[3];
- for(j=0;j<i;j++,q++) {
- if(*q == '-') {
- /* They've already go it.
- */
-
- read_rec(mfl, msg_nr[j][0], (char *)p->mmhs);
- markdis(msg_nr[j][1]); /*extnr*/
- p->mmhs->stat clrbit m_busy;
- if (p->mmhs->ext isnt 1) {
- pcall(p->mmhs->fwdc, fcall);
- p->mmhs->fport = p->id;
- }
- write_rec(mfl, p->mmhs->rn, (char *)p->mmhs);
- makehdr2();
- sprintf(p->line, "%u %s", p->mmhs->number, path);
- log ('M', 'F', ' ', p->line);
- msg_nr[j][0] = 0;
- continue;
- }
- if(*q == '=') {
- /* Deferred ... maybe send it later */
-
- read_rec(mfl, msg_nr[j][0], (char *)p->mmhs);
- p->mmhs->stat clrbit m_busy;
- write_rec(mfl, p->mmhs->rn, (char *)p->mmhs);
- msg_nr[j][0] = 0;
- continue;
- }
- }
-
- /* 3.
- Now do the actual forwarding if there are any left
- */
- q = &fbbreply[3];
- for(j=0;j<i;j++,q++) {
- if(*q != '+') continue;
- /* Handle the case where they want the message .. .send it and
- mark it as sent
- */
- read_rec(mfl, msg_nr[j][0], (char *)p->mmhs);
- if(s_mart & (cmpok|zoook)) {
- /* Compressed protocol uses YAPP. */
- /* snd_yapp returns zero on success */
- if(snd_yapp()) {
- fopts setbit fw_tiout;
- /* Release this one now since it's already in memory */
- p->mmhs->stat clrbit m_busy;
- write_rec(mfl, msg_nr[j][0], (char *)p->mmhs);
- msg_nr[j][0] = 0;
- goto release;
- }
- }
- else {
- /* Otherwise use ASCII protocol */
- outstr(p->mmhs->title);
- outchar('\n');
- curtim();
- prtx(mm[4]);
- /* xmtmsg returns 1 on succes */
- if(!xmtmsg()) {
- fopts setbit fw_tiout;
- /* Release this one now since it's already in memory */
- p->mmhs->stat clrbit m_busy;
- write_rec(mfl, msg_nr[j][0], (char *)p->mmhs);
- msg_nr[j][0] = 0;
- goto release;
- }
- }
- }
- return(0);
- }
-
- /*
- Release those messages whose record numbers remain in msg_nr[*][0].
- If mark is non_zero then mark them as forwarded, otherwise simply
- remove the busy bit and release the record.
- */
- fbb_release(mark)
- int mark;
- {
- register int i;
- register PORTS *p;
-
- p = port;
- for(i=0;i<5;i++) {
- if(msg_nr[i][0]) {
- read_rec(mfl, msg_nr[i][0], (char *)p->mmhs);
- p->mmhs->stat clrbit m_busy;
- if(mark) {
- markdis(msg_nr[i][1]); /*extnr*/
- if (p->mmhs->ext isnt 1) {
- pcall(p->mmhs->fwdc, fcall);
- p->mmhs->fport = p->id;
- }
- }
- write_rec(mfl, msg_nr[i][0], (char *)p->mmhs);
- if(mark) {
- makehdr2();
- sprintf(p->line, "%u %s", p->mmhs->number, path);
- log ('M', 'F', ' ', p->line);
- }
- }
- }
- }
- /* Put all the fields of an FBB proposal into the port->mmhs structure */
- fbb_parse(pp)
- char *pp;
- {
- register char *p,*q;
- register char *qq;
-
- p = pp;
- fill(port->mmhs->fwdc, '\0', ln_call);
- port->mmhs->type = p[3];
- /* Next two are only required so that the correct info will be logged */
- port->opt1 = 'S';
- port->opt2 = p[3];
- p += 5;
- ljsf(port->mmhs->from,p,ln_call);
- while(*p != ' ')p++;
- p++;
- pcall(port->mmhs->bbs, p);
- port->mmhs->ext = 0;
- /* If there's no period in the string or the period occurs after the
- space which follows the BBS, then it's not a hierarchical call.
- In this case it is looked up in states.mb by chkhier()
-
- Otherwise, the hierarchical call is stored.
- */
- if(((qq = strchr(p, '.')) is NULL) || (qq > strchr(p,' '))) {
- chkhier();
- }
- else {
- port->mmhs->ext = 2;
- fill(port->mmhs->call, '\0', 124);
- q = (char *)port->mmhs->call;
- while(*p != ' ')*q++ = *p++;
- }
- while(*p != ' ')p++;
- p++;
- ljsf(port->mmhs->to,p,ln_call);
- while(*p != ' ')p++;
- p++;
- ljsf(port->mmhs->bid,p,ln_bid);
- while(*p != ' ')p++;
- p++;
- port->mmhs->size = atoi(p);
- hasbid = 1;
- }
- /* After a fbb_parse(), test to see if we want this message */
- fbb_test()
- {
- if(test_reject())return(1);
- if(test_bbs()) {
- /* If it's an unknown @BBS in a bulletin and my option is active,
- reject the bulletin.
- */
- if(optflags[0] && (port->mmhs->type == 'B')) {
- return(1);
- }
- }
- checkbid();
- if(!needbid)return(1);
- return(0);
- }
-